package edu.thu.studio.ormdesigner.editor.command;

import java.util.Iterator;

import org.eclipse.gef.commands.Command;

import edu.thu.studio.ormdesigner.model.diagram.link.Link;
import edu.thu.studio.ormdesigner.model.diagram.node.Node;

public class ReconnectLinkCommand extends Command {
    
    private Link link;
    
    private Node newSource;
    private Node newTarget;
    
    private final Node oldSource;
    private final Node oldTarget;
    
    public ReconnectLinkCommand(Link link) {
        if (link == null) {
            throw new IllegalArgumentException();
        }
        this.link = link;
        this.oldSource = link.getSource();
        this.newTarget = this.oldTarget = link.getTarget();
    }
    
    /*
     * (non-Javadoc)
     * 
     * @see org.eclipse.gef.commands.Command#canExecute()
     */
    public boolean canExecute() {
        if (newSource != null) {
            return checkSourceReconnection();
        } else if (newTarget != null) {
            return checkTargetReconnection();
        }
        return false;
    }
    
    private boolean checkSourceReconnection() {
        if (newSource.equals(oldTarget)) {
            return false;
        }
        for (Iterator<Link> iter = newSource.getIncomings().iterator(); iter.hasNext();) {
            Link _link = iter.next();
            if (_link.getTarget().equals(oldTarget) && !_link.equals(link)) {
                return false;
            }
        }
        return true;
    }
    
    private boolean checkTargetReconnection() {
        if (newTarget.equals(oldSource)) {
            return false;
        }
        for (Iterator<Link> iter = newTarget.getOutgoings().iterator(); iter.hasNext();) {
            Link _link = iter.next();
            if (_link.getSource().equals(oldSource) && !_link.equals(link)) {
                return false;
            }
        }
        return true;
    }
    
    public void execute() {
        if (newSource != null) {
            link.reconnect(newSource, oldTarget);
        } else if (newTarget != null) {
            link.reconnect(oldSource, newTarget);
        } else {
            throw new IllegalStateException("Should not happen");
        }
    }
    
    public void setNewSource(Node connectionSource) {
        if (connectionSource == null) {
            throw new IllegalArgumentException();
        }
        setLabel("move connection startpoint");
        newSource = connectionSource;
        newTarget = null;
    }
    
    public void setNewTarget(Node connectionTarget) {
        if (connectionTarget == null) {
            throw new IllegalArgumentException();
        }
        setLabel("move connection endpoint");
        newSource = null;
        newTarget = connectionTarget;
    }
    
    public void undo() {
        link.reconnect(oldSource, oldTarget);
    }
    
}
